﻿package net.wangit.view.chart;

import java.awt.Font;
import java.awt.Paint;
import java.awt.Stroke;

import net.wangit.MapList;
import net.wangit.context.ActionContext;
import net.wangit.context.LocalContext;
import net.wangit.framework.util.MapListUtil;
import net.wangit.framework.util.QueryProcessor;
import net.wangit.framework.util.UnitDataUtil;
import net.wangit.jdbc.DB;
import net.wangit.jdbc.DBFactory;
import net.wangit.jdbc.DBImplementor;
import net.wangit.support.DatasetFactory;
import net.wangit.support.JFreeChartFactory;
import net.wangit.support.JFreeChartSetter;
import net.wangit.support.MapListFactory;
import net.wangit.support.SqlProvider;
import net.wangit.util.Checker;
import net.wangit.util.ClassUtil;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.axis.CategoryAnchor;
import org.jfree.chart.axis.CategoryLabelPositions;
import org.jfree.chart.block.BlockBorder;
import org.jfree.chart.plot.PlotOrientation;
import org.jfree.chart.title.TextTitle;
import org.jfree.data.general.Dataset;
import org.jfree.ui.RectangleEdge;
import org.jfree.ui.RectangleInsets;


public abstract class Chart {
	private static Log log = LogFactory.getLog(Chart.class);
	protected String domain;
	protected int width;
	protected int height;
	protected String title;
	protected String categoryLabel;
	protected String valueLabel;
	private int dataMode;
	private String datasource;
	private String queryUnitId;
	private String tableName;
	private String dataExpression;
	private String factory;
	private String setter;
	protected boolean antiAlias;
	protected Paint backgroundColor;
	protected String backgroundImage;
	protected int backgroundImageAlignment;
	protected float backgroundImageAlpha;
	protected boolean borderVisible;
	protected Stroke borderStroke;
	protected Paint borderColor;
	protected RectangleInsets padding;
	protected Paint[] colors;
	protected PlotOrientation orientation;
	protected Paint plotBackgroundColor;
	protected float plotBackgroundAlpha;
	protected Paint plotOutlineColor;
	protected Stroke plotOutlineStroke;
	protected RectangleInsets plotPadding;
	protected float plotForegroundAlpha;
	protected String itemlabelFormat;
	protected boolean tooltips;
	protected String toolTipFormat;
	protected boolean urls;
	protected String url;
	protected Paint itemOutlineColor;
	protected Stroke itemOutlineStroke;
	protected RectangleEdge titlePosition;
	protected Font titleFont;
	protected Paint titleColor;
	protected Paint titleBackgroundColor;
	protected BlockBorder titleBorder;
	protected TextTitle subTitle;
	protected boolean legend;
	protected RectangleEdge legendPosition;
	protected Font legendFont;
	protected Paint legendColor;
	protected Paint legendBackgroundColor;
	protected BlockBorder legendBorder;
	protected String legendTitle;
	protected boolean domainGridlinesVisible;
	protected Paint domainGridlinesColor;
	protected Stroke domainGridlinesStroke;
	protected CategoryAnchor domainGridlinesPosition;
	protected boolean rangeGridlinesVisible;
	protected Paint rangeGridlinesColor;
	protected Stroke rangeGridlinesStroke;
	protected RectangleInsets axisOffset;
	protected boolean itemLabelsVisible;
	protected double itemLabelAnchorOffset;
	protected int itemLabelsPosition;
	protected boolean categoryAxisVisible;
	protected Paint categoryAxisLabelColor;
	protected Font categoryAxisLabelFont;
	protected Paint categoryAxisTickLabelColor;
	protected Font categoryAxisTickLabelFont;
	protected CategoryLabelPositions categoryAxisCategoryLabelPositions;
	protected boolean numberAxisVisible;
	protected Paint numberAxisLabelColor;
	protected Font numberAxisLabelFont;
	protected Paint numberAxisTickLabelColor;
	protected Font numberAxisTickLabelFont;
	protected double numberAxisUpperMargin;
	protected double numberAxisLowerMargin;
	protected boolean pieCircular;
	protected boolean pieItemOutlinesVisible;
	protected double pieStartAngle;
	protected boolean pieLabelLinksVisible;
	protected String pieExplodePercents;

	public JFreeChart getJFreeChart() {
		JFreeChart chart;
		if (Checker.isEmpty(this.factory))
			chart = createJFreeChart();
		else {
			try {
				JFreeChartFactory chartFactory = (JFreeChartFactory) ClassUtil
						.loadClass(this.factory).newInstance();
				chart = chartFactory.getJFreeChart();
			} catch (Exception e) {
				throw new ChartConfigurationException("factory error:"
						+ this.factory, e);
			}
		}
		if (!(Checker.isEmpty(this.setter))) {
			try {
				JFreeChartSetter chartSetter = (JFreeChartSetter) ClassUtil
						.loadClass(this.setter).newInstance();
				chartSetter.set(chart);
			} catch (Exception e) {
				throw new ChartConfigurationException("setter error:"
						+ this.setter, e);
			}
		}
		return chart;
	}

	protected abstract JFreeChart createJFreeChart();

	protected Dataset getDataset() {
		switch (this.dataMode) {
		case 0:
		case 1:
			try {
				ActionContext ac = LocalContext.getLocalContext()
						.getActionContext();
				DB db = DBFactory.getDB(this.datasource);
				String sql = getOriginalSql(ac);
				if ((!(Checker.isEmpty(this.queryUnitId)))
						&& (!(Checker.isEmpty(this.tableName)))) {
					sql = QueryProcessor.addConditionAndOrder(ac,
							(DBImplementor) db, sql, this.domain,
							this.queryUnitId, this.tableName, null);
				}
				sql = UnitDataUtil.resolveSQL(ac, sql);
				MapList list = db.query(sql);
				return toDataset(list);
			} catch (Exception e) {
				throw new ChartConfigurationException("datasource error:", e);
			}
		case 2:
			try {
				MapListFactory factory = (MapListFactory) ClassUtil.loadClass(
						this.dataExpression).newInstance();
				return toDataset(factory.getMapList());
			} catch (Exception e) {
				throw new ChartConfigurationException("MapListFactory error:",
						e);
			}
		case 3:
			try {
				DatasetFactory factory = (DatasetFactory) ClassUtil.loadClass(
						this.dataExpression).newInstance();
				return factory.getDataset();
			} catch (Exception e) {
				throw new ChartConfigurationException("DatasetFactory error:",
						e);
			}
		case 4:
			try {
				return toDataset(MapListUtil.getMapList(this.dataExpression));
			} catch (Exception e) {
				throw new ChartConfigurationException("datasource error:", e);
			}
		}
		return null;
	}

	protected abstract Dataset toDataset(MapList paramMapList);

	public int getHeight() {
		return this.height;
	}

	protected void setHeight(int height) {
		this.height = height;
	}

	protected void setSetter(String setter) {
		this.setter = setter;
	}

	protected void setTitle(String title) {
		this.title = title;
	}

	public int getWidth() {
		return this.width;
	}

	protected void setWidth(int width) {
		this.width = width;
	}

	protected void setFactory(String factory) {
		this.factory = factory;
	}

	protected void setDataExpression(String dataExpression) {
		if (Checker.isEmpty(dataExpression)) {
			this.dataExpression = dataExpression;
		} else {
			dataExpression = dataExpression.replaceAll("\r\n", " ");
			dataExpression = dataExpression.replaceAll("\r", " ");
			this.dataExpression = dataExpression.replaceAll("\n", " ");
		}
	}

	protected void setDataMode(int dataMode) {
		this.dataMode = dataMode;
	}

	protected void setOrientation(PlotOrientation orientation) {
		this.orientation = orientation;
	}

	protected void setCategoryLabel(String categoryLabel) {
		this.categoryLabel = categoryLabel;
	}

	protected void setValueLabel(String valueLabel) {
		this.valueLabel = valueLabel;
	}

	protected void setLegend(boolean legend) {
		this.legend = legend;
	}

	protected void setTooltips(boolean tooltips) {
		this.tooltips = tooltips;
	}

	protected void setUrls(boolean urls) {
		this.urls = urls;
	}

	protected void setTitleFont(Font titleFont) {
		this.titleFont = titleFont;
	}

	protected void setBackgroundImageAlignment(int backgroundImageAlignment) {
		this.backgroundImageAlignment = backgroundImageAlignment;
	}

	protected void setBackgroundImageAlpha(float backgroundImageAlpha) {
		this.backgroundImageAlpha = backgroundImageAlpha;
	}

	protected void setBackgroundColor(Paint backgroundColor) {
		this.backgroundColor = backgroundColor;
	}

	protected void setBackgroundImage(String backgroundImage) {
		this.backgroundImage = backgroundImage;
	}

	protected void setBorderVisible(boolean borderVisible) {
		this.borderVisible = borderVisible;
	}

	protected void setBorderStroke(Stroke borderStroke) {
		this.borderStroke = borderStroke;
	}

	protected void setBorderColor(Paint borderColor) {
		this.borderColor = borderColor;
	}

	protected void setAntiAlias(boolean antiAlias) {
		this.antiAlias = antiAlias;
	}

	protected void setPadding(RectangleInsets padding) {
		this.padding = padding;
	}

	protected void setTitleBackgroundColor(Paint titleBackgroundColor) {
		this.titleBackgroundColor = titleBackgroundColor;
	}

	protected void setTitleColor(Paint titleColor) {
		this.titleColor = titleColor;
	}

	protected void setTitlePosition(RectangleEdge titlePosition) {
		this.titlePosition = titlePosition;
	}

	protected void setTitleBorder(BlockBorder titleBorder) {
		this.titleBorder = titleBorder;
	}

	protected void setLegendPosition(RectangleEdge legendPosition) {
		this.legendPosition = legendPosition;
	}

	protected void setLegendBackgroundColor(Paint legendBackgroundColor) {
		this.legendBackgroundColor = legendBackgroundColor;
	}

	protected void setLegendColor(Paint legendColor) {
		this.legendColor = legendColor;
	}

	protected void setLegendFont(Font legendFont) {
		this.legendFont = legendFont;
	}

	protected void setLegendBorder(BlockBorder legendBorder) {
		this.legendBorder = legendBorder;
	}

	protected void setPlotBackgroundAlpha(float plotBackgroundAlpha) {
		this.plotBackgroundAlpha = plotBackgroundAlpha;
	}

	protected void setPlotOutlineStroke(Stroke plotOutlineStroke) {
		this.plotOutlineStroke = plotOutlineStroke;
	}

	protected void setPlotBackgroundColor(Paint plotBackgroundColor) {
		this.plotBackgroundColor = plotBackgroundColor;
	}

	protected void setPlotOutlineColor(Paint plotOutlineColor) {
		this.plotOutlineColor = plotOutlineColor;
	}

	protected void setPlotPadding(RectangleInsets plotPadding) {
		this.plotPadding = plotPadding;
	}

	protected void setPlotForegroundAlpha(float plotForegroundAlpha) {
		this.plotForegroundAlpha = plotForegroundAlpha;
	}

	protected void setDomainGridlinesColor(Paint domainGridlinesColor) {
		this.domainGridlinesColor = domainGridlinesColor;
	}

	protected void setDomainGridlinesPosition(
			CategoryAnchor domainGridlinesPosition) {
		this.domainGridlinesPosition = domainGridlinesPosition;
	}

	protected void setDomainGridlinesStroke(Stroke domainGridlinesStroke) {
		this.domainGridlinesStroke = domainGridlinesStroke;
	}

	protected void setDomainGridlinesVisible(boolean domainGridlinesVisible) {
		this.domainGridlinesVisible = domainGridlinesVisible;
	}

	protected void setRangeGridlinesColor(Paint rangeGridlinesColor) {
		this.rangeGridlinesColor = rangeGridlinesColor;
	}

	protected void setRangeGridlinesStroke(Stroke rangeGridlinesStroke) {
		this.rangeGridlinesStroke = rangeGridlinesStroke;
	}

	protected void setRangeGridlinesVisible(boolean rangeGridlinesVisible) {
		this.rangeGridlinesVisible = rangeGridlinesVisible;
	}

	protected void setAxisOffset(RectangleInsets axisOffset) {
		this.axisOffset = axisOffset;
	}

	protected void setCategoryAxisCategoryLabelPositions(
			CategoryLabelPositions categoryAxisCategoryLabelPositions) {
		this.categoryAxisCategoryLabelPositions = categoryAxisCategoryLabelPositions;
	}

	protected void setCategoryAxisLabelColor(Paint categoryAxisLabelColor) {
		this.categoryAxisLabelColor = categoryAxisLabelColor;
	}

	protected void setCategoryAxisLabelFont(Font categoryAxisLabelFont) {
		this.categoryAxisLabelFont = categoryAxisLabelFont;
	}

	protected void setCategoryAxisTickLabelColor(
			Paint categoryAxisTickLabelColor) {
		this.categoryAxisTickLabelColor = categoryAxisTickLabelColor;
	}

	protected void setCategoryAxisTickLabelFont(Font categoryAxisTickLabelFont) {
		this.categoryAxisTickLabelFont = categoryAxisTickLabelFont;
	}

	protected void setCategoryAxisVisible(boolean categoryAxisVisible) {
		this.categoryAxisVisible = categoryAxisVisible;
	}

	protected void setNumberAxisLabelColor(Paint numberAxisLabelColor) {
		this.numberAxisLabelColor = numberAxisLabelColor;
	}

	protected void setNumberAxisLabelFont(Font numberAxisLabelFont) {
		this.numberAxisLabelFont = numberAxisLabelFont;
	}

	protected void setNumberAxisLowerMargin(double numberAxisLowerMargin) {
		this.numberAxisLowerMargin = numberAxisLowerMargin;
	}

	protected void setNumberAxisTickLabelColor(Paint numberAxisTickLabelColor) {
		this.numberAxisTickLabelColor = numberAxisTickLabelColor;
	}

	protected void setNumberAxisTickLabelFont(Font numberAxisTickLabelFont) {
		this.numberAxisTickLabelFont = numberAxisTickLabelFont;
	}

	protected void setNumberAxisUpperMargin(double numberAxisUpperMargin) {
		this.numberAxisUpperMargin = numberAxisUpperMargin;
	}

	protected void setNumberAxisVisible(boolean numberAxisVisible) {
		this.numberAxisVisible = numberAxisVisible;
	}

	protected void setUrl(String url) {
		this.url = url;
	}

	protected void setPieCircular(boolean pieCircular) {
		this.pieCircular = pieCircular;
	}

	protected void setPieExplodePercents(String pieExplodePercents) {
		this.pieExplodePercents = pieExplodePercents;
	}

	protected void setPieLabelLinksVisible(boolean pieLabelLinksVisible) {
		this.pieLabelLinksVisible = pieLabelLinksVisible;
	}

	protected void setPieStartAngle(double pieStartAngle) {
		this.pieStartAngle = pieStartAngle;
	}

	protected void setItemLabelAnchorOffset(double itemLabelAnchorOffset) {
		this.itemLabelAnchorOffset = itemLabelAnchorOffset;
	}

	protected void setItemLabelsVisible(boolean itemLabelsVisible) {
		this.itemLabelsVisible = itemLabelsVisible;
	}

	protected void setItemOutlineColor(Paint itemOutlineColor) {
		this.itemOutlineColor = itemOutlineColor;
	}

	protected void setItemOutlineStroke(Stroke itemOutlineStroke) {
		this.itemOutlineStroke = itemOutlineStroke;
	}

	protected void setPieItemOutlinesVisible(boolean pieItemOutlinesVisible) {
		this.pieItemOutlinesVisible = pieItemOutlinesVisible;
	}

	protected void setItemlabelFormat(String itemlabelFormat) {
		this.itemlabelFormat = itemlabelFormat;
	}

	protected void setToolTipFormat(String toolTipFormat) {
		this.toolTipFormat = toolTipFormat;
	}

	protected void setColors(Paint[] colors) {
		this.colors = colors;
	}

	protected void setSubTitle(TextTitle subTitle) {
		this.subTitle = subTitle;
	}

	protected void setItemLabelsPosition(int itemLabelsPosition) {
		this.itemLabelsPosition = itemLabelsPosition;
	}

	protected void setDatasource(String datasource) {
		this.datasource = datasource;
	}

	protected void setQueryUnitId(String queryUnitId) {
		this.queryUnitId = queryUnitId;
	}

	protected void setTableName(String tableName) {
		this.tableName = tableName;
	}

	protected void setDomain(String domain) {
		this.domain = domain;
	}

	private String getOriginalSql(ActionContext ac) throws Exception {
		if (this.dataMode == 0) {
			try {
				SqlProvider provider = (SqlProvider) ClassUtil.loadClass(
						this.dataExpression).newInstance();
				return provider.getSql(ac);
			} catch (Exception e) {
				log.error("Chart SqlProvider error : " + this.dataExpression);
				throw e;
			}
		}
		return this.dataExpression;
	}
}